home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
asm_0_m.arj
/
FMT.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-23
|
78KB
|
2,855 lines
;***********************************************************************
;* *
;* Fmt.asm 23-JAN-1990 *
;* *
;* Format Floppy Disk - version 1.00 - IBM(R) DOS 4.0 style format *
;* *
;* Designed for use with IBM AT compatible sytems (including PS/2s) *
;* *
;* Syntax: FMT d: size [v] [s] [n] *
;* *
;* where: d = drive (A or B), size = floppy size in Kb, *
;* *
;* the optional v enables format verification, *
;* *
;* the optional s copies the system files, *
;* *
;* and the optional n bypasses the `insert floppy' prompt *
;* *
;* supported sizes are: *
;* *
;* 360 for a 360 Kb floppy in a 360 Kb or 1.2 Mb drive *
;* 720 for a 720 Kb floppy in a 720 Kb or 1.44 Mb drive *
;* 1200 for a 1.2 Mb floppy in a 1.2 Mb drive *
;* 1440 for a 1.44 Mb floppy in a 1.44 Mb drive *
;* *
;* Exit codes: *
;* *
;* 0 = successful format *
;* 1 = failure during format, verify, or write *
;* 2 = disk size / drive type combination is not supported *
;* 3 = requested drive does not exist *
;* 4 = invalid or null command line *
;* 5 = system files not found or error writing system files *
;* 6 = computer is not AT compatible *
;* 7 = insufficient memory for file copy buffer (system transfer) *
;* *
;* In order to use the system transfer option, the following files *
;* *
;* must be in the root diectory of the default drive: *
;* *
;* 1: IBMBIO.COM (normally a hidden file) *
;* *
;* 2: IBMDOS.COM (normally a hidden file) *
;* *
;* 3: COMMAND.COM *
;* *
;* Compile with Borland Turbo Assembler(R) version 1.0 or greater *
;* *
;* tasm /t fmt tasm /t /zi fmt *
;* or *
;* tlink /t /x fmt tlink /v /x fmt *
;* *
;* tdstrip -c -s fmt *
;* *
;* for use with Turbo Debugger(R) *
;* or *
;* *
;* Compile with Microsoft(R) Macro Assembler version 5.1 or greater *
;* *
;* masm /t fmt; *
;* *
;* link fmt; *
;* *
;* exe2bin fmt fmt.com *
;* *
;* del fmt.exe *
;* *
;* Copyright (C) 1990 by: *
;* *
;* Clair Alan Hardesty *
;* IBM-PC Hardware/Software Consultant *
;* 10301 Johnson Av *
;* Cupertino, CA 95014 *
;* (408) 446-0550 *
;* CompuServe 75350,16 *
;* *
;* Microsoft(R) is a registered trademark of Microsoft Corporation *
;* *
;* IBM(R) and PS/2 are registered trademarks of International *
;* *
;* Business Machines Corporation *
;* *
;* Turbo Assembler(R) and Turbo Debugger(R) are registered trademarks *
;* *
;* of Borland International *
;* *
;***********************************************************************
;***********************************************************************
; set-up for the far jump used in the boot record code
;***********************************************************************
ibmbio segment at 0070h
assume cs:ibmbio
org 0000h
program_loader label far
ibmbio ends
;***********************************************************************
; set-up for system identification
;***********************************************************************
rom_bios segment at 0f000h
assume ds:rom_bios
org 0fffeh
system_id label byte
rom_bios ends
;***********************************************************************
; main program code
;***********************************************************************
cseg segment
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 0100h
entry_point:
jmp start ; skip over data area
;***********************************************************************
; format data area
;***********************************************************************
; format sector tables
sector_table_0:
db 000h,000h,001h,002h
db 000h,000h,002h,002h
db 000h,000h,003h,002h
db 000h,000h,004h,002h
db 000h,000h,005h,002h
db 000h,000h,006h,002h
db 000h,000h,007h,002h
db 000h,000h,008h,002h
db 000h,000h,009h,002h
db 000h,000h,00Ah,002h
db 000h,000h,00Bh,002h
db 000h,000h,00Ch,002h
db 000h,000h,00Dh,002h
db 000h,000h,00Eh,002h
db 000h,000h,00Fh,002h
db 000h,000h,010h,002h
db 000h,000h,011h,002h
db 000h,000h,012h,002h
sector_table_1:
db 000h,001h,001h,002h
db 000h,001h,002h,002h
db 000h,001h,003h,002h
db 000h,001h,004h,002h
db 000h,001h,005h,002h
db 000h,001h,006h,002h
db 000h,001h,007h,002h
db 000h,001h,008h,002h
db 000h,001h,009h,002h
db 000h,001h,00Ah,002h
db 000h,001h,00Bh,002h
db 000h,001h,00Ch,002h
db 000h,001h,00Dh,002h
db 000h,001h,00Eh,002h
db 000h,001h,00Fh,002h
db 000h,001h,010h,002h
db 000h,001h,011h,002h
db 000h,001h,012h,002h
;***********************************************************************
temp_size: db 4 dup (?)
binary_size: dw ?
verify: db 0 ; default is no verification
system: db 0 ; default is no system file transfer
prompt: db 1 ; default is prompt for floppy
drive_number: db ?
disk_drive: dw ?
max_track: db ?
retry_count: db ?
write_track: dw ?
write_head: db ?
write_sector: db ?
cursor: dw ?
stack_size: dw 2048 ; used in buffer size calculation
minimum_buffer: dw 4096 ; minimum file copy buffer size
buffer_size: dw ? ; actual file copy buffer size
;***********************************************************************
disk_size: db ?
; 1 = 360kb
; 2 = 1.2Mb
; 3 = 720kb
; 4 = 1.44Mb
drive_type: db ?
; 0 = no drive
; 1 = 360kb
; 2 = 1.2Mb
; 3 = 720kb
; 4 = 1.44Mb
;***********************************************************************
parameter_pointer:
dd ? ; storage for the original disk parameter table pointer
;***********************************************************************
floppy_table:
; 360 Kb
db 0FDh ; media descriptor
db 40 ; number of tracks
dw 9 ; sectors per track
dw 112 ; entries per root directory
db 7 ; sectors per root directory
db 2 ; sectors per cluster
dw 2 ; sectors per FAT
; 1.2 Mb
db 0F9h ; media descriptor
db 80 ; number of tracks
dw 15 ; sectors per track
dw 224 ; entries per root directory
db 14 ; sectors per root directory
db 1 ; sectors per cluster
dw 7 ; sectors per FAT
; 720 Kb
db 0F9h ; media descriptor
db 80 ; number of tracks
dw 9 ; sectors per track
dw 112 ; entries per root directory
db 7 ; sectors per root directory
db 2 ; sectors per cluster
dw 3 ; sectors per FAT
; 1.44 Mb
db 0F0h ; media descriptor
db 80 ; number of tracks
dw 18 ; sectors per track
dw 224 ; entries per root directory
db 14 ; sectors per root directory
db 1 ; sectors per cluster
dw 9 ; sectors per FAT
;***********************************************************************
parameter_table:
; 360 Kb
db 0D2h,002h,009h,002h,009h,02Ah,0FFh,050h,0F6h,001h,001h
; 1.2 Mb
db 082h,002h,009h,002h,00Fh,01Bh,0FFh,054h,0F6h,001h,001h
; 720 Kb
db 012h,002h,009h,002h,009h,02Ah,0FFh,050h,0F6h,001h,001h
; 1.44 Mb
db 012h,002h,009h,002h,012h,01Bh,0FFh,06Ch,0F6h,001h,001h
;***********************************************************************
; informational messages
;***********************************************************************
cr_lf:
db 00Dh,00Ah
db "$"
insert_floppy:
db "Put desired floppy in drive "
insert_drive:
db ?
db ": and press any key"
db "$"
clear_line:
db 50 dup (008h)
db 50 dup (020h)
db 50 dup (008h)
db "$"
format_display:
db 26 dup (008h)
db "Formatting track "
format_track_number:
db 2 dup (?)
db " head "
format_head_number:
db ?
db "$"
verify_display:
db 26 dup (008h)
db "Verifying track "
verify_track_number:
db 2 dup (?)
db " head "
verify_head_number:
db ?
db "$"
boot_message:
db 26 dup (008h)
db 26 dup (020h)
db 26 dup (008h)
db "Writing boot record"
db "$"
fat_message:
db 19 dup (008h)
db 19 dup (020h)
db 19 dup (008h)
db "Writing FATs"
db "$"
dir_message:
db 12 dup (008h)
db 12 dup (020h)
db 12 dup (008h)
db "Writing root directory"
db "$"
file_copy_message:
db 22 dup (008h)
db 22 dup (020h)
db 22 dup (008h)
db "Copying system files"
db "$"
exit_message:
db 22 dup (008h)
db 22 dup (020h)
db 22 dup (008h)
db "Format complete"
db 00Dh,00Ah
db "$"
;***********************************************************************
; error messages
;***********************************************************************
computer_message:
db 00Dh,00Ah,"IBM AT or compatible computer required",00Dh,00Ah
db "$"
no_drive_error:
db 00Dh,00Ah,"No such drive in system",00Dh,00Ah
db "$"
reset_error:
db 00Dh,00Ah,"Disk controller reset error",00Dh,00Ah
db "$"
set_drive_error:
db 00Dh,00Ah,"Disk drive type not supported by BIOS",00Dh,00Ah
db "$"
no_floppy_error:
db 00Dh,00Ah,"No floppy in drive",00Dh,00Ah
db "$"
set_disk_error:
db 00Dh,00Ah,"Disk / Drive combination not supported",00Dh,00Ah
db "$"
write_boot_error:
db 00Dh,00Ah,"Error writing boot record",00Dh,00Ah
db "$"
write_fat_error:
db 00Dh,00Ah,"Error writing FAT",00Dh,00Ah
db "$"
write_dir_error:
db 00Dh,00Ah,"Error writing directory",00Dh,00Ah
db "$"
write_protect_error:
db 00Dh,00Ah,"Disk is write protected",00Dh,00Ah
db "$"
error_during_format:
db 00Dh,00Ah,"Error during format",00Dh,00Ah
db "$"
disk_type_error:
db 00Dh,00Ah,"Probably wrong floppy type",00Dh,00Ah
db "$"
verify_error:
db 00Dh,00Ah,"Verification error",00Dh,00Ah
db "$"
buffer_space_error:
db 00Dh,00Ah,"No room for file copy buffer",00Dh,00Ah
db "$"
help_message:
db 00Dh,00Ah,"FMT version 1.00, Copyright (C) 1990 Clair Alan Hardesty"
db 00Dh,00Ah
db 00Dh,00Ah," syntax: fmt d: size [v] [s] [n]"
db 00Dh,00Ah
db 00Dh,00Ah," where: d = drive (A or B), size = floppy size in Kb,"
db 00Dh,00Ah
db 00Dh,00Ah," the optional v enables format verification,"
db 00Dh,00Ah
db 00Dh,00Ah," the optional s copies the system files,"
db 00Dh,00Ah
db 00Dh,00Ah," and the optional n bypasses the `insert floppy' prompt"
db 00Dh,00Ah
db 00Dh,00Ah," supported sizes are:"
db 00Dh,00Ah
db 00Dh,00Ah," 360 for a 360 Kb floppy in a 360 Kb or 1.2 Mb drive"
db 00Dh,00Ah," 720 for a 720 Kb floppy in a 720 Kb or 1.44 Mb drive"
db 00Dh,00Ah," 1200 for a 1.2 Mb floppy in a 1.2 Mb drive"
db 00Dh,00Ah," 1440 for a 1.44 Mb floppy in a 1.44 Mb drive"
db 00Dh,00Ah
db "$"
;***********************************************************************
; check cpu and computer type
;***********************************************************************
start:
; check CPU for 80286 or above
xor ax,ax
push ax
popf
pushf
pop ax
and ax,08000h
cmp ax,08000h
jnz two_eighty_six
mov dx,offset computer_message
mov ah,09h
int 21h
; exit
jmp short not_an_at
two_eighty_six:
; check the model byte in ROM
push ds
mov ax,rom_bios
mov ds,ax
assume ds:rom_bios
cmp system_id,0fch ; AT or compatible
je at_or_better
cmp system_id,0fah ; most P/S-2 (80286) models
je at_or_better
cmp system_id,0f8h ; P/S-2 model 80
je at_or_better
; computer is not AT compatible
pop ds
assume ds:cseg
mov dx,offset computer_message
mov ah,09h
int 21h
not_an_at:
; set exit code to 6 (not an AT or compatible)
mov ax,4c06h
int 21h
at_or_better:
;***********************************************************************
.286 ; enable the 80286 instruction set
;***********************************************************************
pop ds
assume ds:cseg
; initialize some variables
mov cl,0 ; parameter counter
mov dl,0 ; disk size digit counter
mov di,offset temp_size ; temporary disk size storage
mov bx,0080h ; pointer to command line
;***********************************************************************
; parse the command line
;***********************************************************************
parse_loop:
inc bx
cmp byte ptr [bx],0dh ; carriage return
jne not_finished
jmp got_command
not_finished:
cmp byte ptr [bx],' ' ; space
je parse_loop
cmp byte ptr [bx],09h ; tab
je parse_loop
cmp cl,0
jg number_check
and byte ptr [bx],5fh ; capitalize drive letter
cmp byte ptr [bx],'A'
jnl check_for_b
jmp help ; invalid drive
check_for_b:
cmp byte ptr [bx],'B'
jng store_drive
jmp help ; invalid drive
store_drive:
mov al,byte ptr [bx]
sub al,'A'
mov byte ptr [drive_number],al
colon_check:
cmp byte ptr [bx+1],':'
je found_colon
jmp help ; no colon after drive letter
found_colon:
inc bx ; skip over the colon
inc cl ; increment parameter count
jmp parse_loop
number_check:
cmp cl,1
jg check_option
cmp byte ptr [bx],'0'
jnl maybe_a_number
jmp help ; not a number
maybe_a_number:
cmp byte ptr [bx],'9'
jng is_a_number
jmp help ; not a number
is_a_number:
cmp byte ptr [bx+1],0Dh ; next character is a return
je last_digit
cmp byte ptr [bx+1],' ' ; next character is a space
je last_digit
cmp byte ptr [bx+1],09h ; next character is a tab
jne store_digit
last_digit:
inc cl ; increment parameter count
store_digit:
mov al,byte ptr [bx]
sub al,'0' ; convert ASCII to BCD
mov byte ptr [di],al
inc di
inc dl
cmp dl,4
jle jump_to_parse
jmp help ; too many digits in disk size
jump_to_parse:
jmp parse_loop
check_option:
cmp cl,5
jng parse_option
jmp help ; too many parameters
parse_option:
and byte ptr [bx],5fh
cmp byte ptr [bx],'V'
je set_verify
cmp byte ptr [bx],'S'
je set_system
cmp byte ptr [bx],'N'
je clear_prompt
jmp help ; invalid option
set_verify:
mov byte ptr [verify],1 ; set format verify true
inc cl
jmp parse_loop
set_system:
mov byte ptr [system],1 ; set transfer system true
inc cl
jmp parse_loop
clear_prompt:
mov byte ptr [prompt],0 ; set transfer system true
inc cl
jmp parse_loop
got_command:
cmp cl,2
jnl two_parameters
jmp help ; too few parameters
two_parameters:
cmp dl,3
jl help ; too few digits in disk size
; convert the size parameter from BCD to binary
mov cl,dl
dec di
xor ah,ah
mov al,byte ptr [di]
mov word ptr [binary_size],ax
dec di
dec cl
xor ah,ah
mov al,byte ptr [di]
imul ax,10
add word ptr [binary_size],ax
dec di
dec cl
xor ah,ah
mov al,byte ptr [di]
imul ax,100
add word ptr [binary_size],ax
dec di
dec cl
jz test_size_360
xor ah,ah
mov al,byte ptr [di]
imul ax,1000
add word ptr [binary_size],ax
test_size_360:
cmp word ptr [binary_size],360
jne test_size_1200 ; not 360 Kb
mov byte ptr [disk_size],1
jmp short set_up ; command line is valid
test_size_1200:
cmp word ptr [binary_size],1200
jne test_size_720 ; not 1.2 Mb
mov byte ptr [disk_size],2
jmp short set_up ; command line is valid
test_size_720:
cmp word ptr [binary_size],720
jne test_size_1440 ; not 720 Kb
mov byte ptr [disk_size],3
jmp short set_up ; command line is valid
test_size_1440:
cmp word ptr [binary_size],1440
jne help ; not 1.44 Mb
mov byte ptr [disk_size],4
jmp short set_up ; command line is valid
help:
; command line is invalid or null
mov dx,offset help_message
mov ah,09h
int 21h
; set exit code to 4 (null or invalid command line)
mov ax,4c04h
int 21h
;***********************************************************************
; set up the drive parameters and the parameter table
;***********************************************************************
set_up:
; if transfering system, check file copy buffer space
cmp byte ptr [system],1
jne cursor_off
; calculate copy buffer size
mov ax,sp
cmp ax,offset file_buffer
jc no_buffer
sub ax,offset file_buffer
sbb ax,word ptr [stack_size]
jc no_buffer
cmp ax,word ptr [minimum_buffer]
jnc buffer_ok
no_buffer:
mov dx,offset buffer_space_error
mov ah,09h
int 21h
; set exit code to 7 (no room for file copy buffer)
mov ax,4c07h
int 21h
buffer_ok:
mov word ptr [buffer_size],ax
cursor_off:
; save the current cursor and then turn the cursor off
mov ah,03h
int 10h
mov word ptr [cursor],cx
or cx,2000h
mov ah,01h
int 10h
; issue a carrriage-return / line-feed to stdout
mov dx,offset cr_lf
mov ah,09h
int 21h
; check for prompt bypass
cmp byte ptr [prompt],1
jne no_prompt
; prompt for a floppy
mov dx,offset insert_floppy
mov ah,09h
mov al,byte ptr [drive_number]
add al,41h
mov byte ptr [insert_drive],al
int 21h
; wait for a key press
xor ah,ah
int 16h
; clear the message line
mov dx,offset clear_line
mov ah,09h
int 21h
no_prompt:
; get disk drive information
push es
push di
push si
mov ah,08h
mov dl,byte ptr [drive_number]
int 13h
cmp bl,0
jne drive_exists
mov dx,offset no_drive_error
mov ah,09h
int 21h
; set exit code to 3 (drive does not exist)
pop ax
pop ax
pop ax
mov ax,4c03h
int 21h
drive_exists:
mov byte ptr [max_track],ch
mov byte ptr [sectors_track],cl
mov byte ptr [drive_type],bl
mov ah,byte ptr [disk_size]
mov al,bl
mov word ptr [disk_drive],ax
; check for floppy size less than drive maximum capacity
; check for a 360 Kb floppy in a 1.2 Mb drive
cmp word ptr [disk_drive],0102h
je forty_tracks
; check for a 720 Kb floppy in a 1.44 Mb drive
cmp word ptr [disk_drive],0304h
je nine_sectors
; check for improper disk / drive cominations
cmp word ptr [disk_drive],0201h
je bad_size ; 1.2 Mb in 360 Kb
cmp word ptr [disk_drive],0301h
je bad_size ; 720 Kb in 360 Kb
cmp word ptr [disk_drive],0401h
je bad_size ; 1.44 Mb in 360 Kb
cmp word ptr [disk_drive],0302h
je bad_size ; 720 Kb in 1.2 Mb
cmp word ptr [disk_drive],0402h
je bad_size ; 1.44 Mb in 1.2 Mb
cmp word ptr [disk_drive],0103h
je bad_size ; 360 Kb in 720 Kb
cmp word ptr [disk_drive],0203h
je bad_size ; 1.2 Mb in 720 Kb
cmp word ptr [disk_drive],0403h
je bad_size ; 1.44 Mb in 720 Kb
cmp word ptr [disk_drive],0104h
je bad_size ; 360 Kb in 1.44 Mb
cmp word ptr [disk_drive],0204h
je bad_size ; 1.2 Mb in 1.44 Mb
jmp short size_ok
bad_size:
mov dx,offset set_disk_error
mov ah,09h
int 21h
; set exit code to 2 (disk / drive comination error)
pop ax
pop ax
pop ax
mov ax,4c02h
int 21h
forty_tracks:
mov byte ptr [max_track],39
nine_sectors:
mov byte ptr [sectors_track],9
size_ok:
; save the original disk parameter table pointer
xor ax,ax
mov es,ax
mov ax,word ptr es:[0078h]
mov dx,word ptr es:[007ah]
mov word ptr [parameter_pointer],ax
mov word ptr [parameter_pointer+2],dx
; set the disk parameter table pointer for formatting
xor ah,ah
mov al,byte ptr [disk_size]
dec ax
imul ax,11
add ax,offset parameter_table
cli
mov word ptr es:[0078h],ax
mov word ptr es:[007ah],cs
sti
; put the parameter table in the boot record
push cs
pop es
mov si,ax
mov di,offset disk_table
mov cx,11
cld
rep movsb
pop si
pop di
pop es
;***********************************************************************
; store the disk parameters in the boot record and FAT
;***********************************************************************
push si
; calculate the offset to the parameters in floppy_table
xor ah,ah
mov al,byte ptr [disk_size]
dec ax
imul ax,10
mov bx,ax
mov si,offset floppy_table
; set the media descriptor byte
mov al,byte ptr [si+bx]
mov byte ptr [descriptor],al
mov byte ptr [fat_record],al ; first byte of FAT
; set the number of root directory entries
mov ax,word ptr [si+bx+4]
mov word ptr [directory_size],ax
; set the number of sectors per directory
mov al,byte ptr [si+bx+6]
mov byte ptr [sectors_directory],al
; set the number of sectors per cluster
mov al,byte ptr [si+bx+7]
mov byte ptr [sectors_cluster],al
; set the number of sectors per FAT
mov ax,word ptr [si+bx+8]
mov word ptr [sectors_fat],ax
; set the total number of sectors per disk
xor dx,dx
xor ah,ah
mov al,byte ptr [max_track]
inc ax
mul word ptr [sectors_track]
xor bh,bh
mov bl,byte ptr [heads]
mul bx
mov word ptr [small_total],ax
; calculate the location of the first directory sector
xor dx,dx
xor ah,ah
mov al,byte ptr [fats]
mul word ptr [sectors_fat]
add ax,word ptr [hidden_sectors]
adc dx,word ptr [hidden_sectors+2]
add ax,word ptr [reserved_sectors]
adc dx,0
; store directory start sector (absolute sector number)
mov word ptr [dir_start],ax
mov word ptr [dir_start+2],dx
; calculate the location of the first data sector
xor bh,bh
mov bl,byte ptr [sectors_directory]
add ax,bx
adc dx,0
; store data start sector (absolute sector number)
mov word ptr [data_start],ax
mov word ptr [data_start+2],dx
pop si
;***********************************************************************
; reset the disk controller
;***********************************************************************
reset:
mov byte ptr [retry_count],3
reset_retry:
xor ah,ah
mov dl,byte ptr [drive_number]
int 13h
jnc short set_drive
dec byte ptr [retry_count]
jnz reset_retry
mov dx,offset reset_error
jmp write_error
;***********************************************************************
; set the drive type for format
;***********************************************************************
set_drive:
mov byte ptr [retry_count],3
drive_retry:
mov al,byte ptr [drive_type]
cmp al,3
jl five_inch
mov al,4
jmp short set_type
five_inch:
cmp al,2
jne low_density
cmp byte ptr [disk_size],1
jg high_density
mov al,2
jmp short set_type
high_density:
mov al,3
jmp short set_type
low_density:
mov al,1
set_type:
mov ah,17h
int 13h
jnc short set_disk
cmp ah,80h
jne floppy_exists
mov dx,offset no_floppy_error
jmp write_error
floppy_exists:
dec byte ptr [retry_count]
jnz drive_retry
mov dx,offset set_drive_error
jmp write_error
;***********************************************************************
; set the disk type for format
;***********************************************************************
set_disk:
mov byte ptr [retry_count],3
disk_retry:
push es
push di
mov ah,18h
mov ch,byte ptr [max_track]
mov cl,byte ptr [sectors_track]
mov dl,byte ptr [drive_number]
int 13h
pop di
pop es
jnc format_disk
dec byte ptr [retry_count]
jnz disk_retry
mov dx,offset set_disk_error
jmp write_error
;***********************************************************************
; format the disk
;***********************************************************************
format_disk:
; set up the loop counter
xor ch,ch
mov cl,byte ptr [max_track]
inc cx
format_loop:
push cx
call format_track
jnc continue
pop cx
jmp write_error
continue:
call next_track
pop cx
loop format_loop
;***********************************************************************
; set up the volume serial number in the boot record
;***********************************************************************
serial_number:
; get the time
mov ah,2ch
int 21h
; fiddle the serial number bytes (similar to DOS 4.0)
;
; I don't know why IBM does this. It may be done to
; hide the fact that the serial number is derived
; from the system clock.
;
; I am not sure that the numbers that I have chosen are
; the same as IBM's, but they are close.
;
; a more reasonable approach might be to simply add one
; to each byte to avoid zero bytes in the serial number
add cx,07c7h
add dx,0707h
; store the serial number in the boot record
mov word ptr [sn_low],cx
mov word ptr [sn_high],dx
;***********************************************************************
; write the boot record and FAT1
;***********************************************************************
write_boot:
mov dx,offset boot_message
mov ah,09h
int 21h
mov byte ptr [retry_count],3
boot_retry:
mov ax,0302h
mov bx,offset boot_record
mov cx,0001h
xor dh,dh
mov dl,byte ptr [drive_number]
int 13h
jnc short finish_fat1
dec byte ptr [retry_count]
jnz boot_retry
mov dx,offset write_boot_error
jmp write_error
finish_fat1:
mov dx,offset fat_message
mov ah,09h
int 21h
; set the starting sector (absolute)
mov ax,2
xor dx,dx
; set the number of sectors to write
mov cx,word ptr [sectors_fat]
dec cx
fat1:
push ax
push cx
push dx
call write_ths
jnc fat1_ths_ok
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp write_error
fat1_ths_ok:
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
fat1_retry:
call write_disk
jnc fat1_write_ok
dec byte ptr [retry_count]
jnz fat1_retry
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp write_error
fat1_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
adc dx,0
loop fat1
jnc write_fat
mov dx,offset write_fat_error
jmp write_error
;***********************************************************************
; write FAT2
;***********************************************************************
write_fat:
mov byte ptr [retry_count],3
fat_retry:
mov ax,0301h
mov bx,offset fat_record
xor ch,ch
mov cl,byte ptr [sectors_fat]
add cl,2
xor dh,dh
mov dl,byte ptr [drive_number]
int 13h
jnc finish_fat2
dec byte ptr [retry_count]
jnz fat_retry
mov dx,offset write_fat_error
jmp write_error
finish_fat2:
; set the starting sector (absolute)
mov ax,2
xor dx,dx
add ax,word ptr [sectors_fat]
adc dx,0
; set the number of sectors to write
mov cx,word ptr [sectors_fat]
dec cx
fat2:
push ax
push cx
push dx
call write_ths
jnc fat2_ths_ok
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp write_error
fat2_ths_ok:
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
fat2_retry:
call write_disk
jnc fat2_write_ok
dec byte ptr [retry_count]
jnz fat2_retry
pop ax
pop ax
pop ax
mov dx,offset write_fat_error
jmp short write_error
fat2_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
adc dx,0
loop fat2
jnc write_dir
mov dx,offset write_fat_error
jmp short write_error
;***********************************************************************
; write the directory
;***********************************************************************
write_dir:
mov dx,offset dir_message
mov ah,09h
int 21h
; set the starting sector (absolute)
xor dx,dx
mov ax,word ptr [sectors_fat]
mul byte ptr [fats]
add ax,word ptr [reserved_sectors]
adc dx,0
; set the number of sectors to write
xor ch,ch
mov cl,byte ptr [sectors_directory]
dir:
push ax
push cx
push dx
call write_ths
jnc dir_ths_ok
pop ax
pop ax
pop ax
mov dx,offset write_dir_error
jmp short write_error
dir_ths_ok:
mov bx,offset fat_dir_record
mov byte ptr [retry_count],3
dir_retry:
call write_disk
jnc dir_write_ok
dec byte ptr [retry_count]
jnz dir_retry
pop ax
pop ax
pop ax
mov dx,offset write_dir_error
jmp short write_error
dir_write_ok:
pop dx
pop cx
pop ax
; increment the absolute sector number
add ax,1
adc dx,0
loop dir
jnc transfer
mov dx,offset write_dir_error
jmp short write_error
transfer:
cmp byte ptr [system],1
jne exit
; transfer the system files
call load_system
jnc exit
; set exit code to 5 (error copying system files)
mov ax,4c05h
push ax
jmp short error_exit
write_error:
mov ah,09h
int 21h
; set exit code to 1 (format, verify, or write error)
mov ax,4c01h
push ax
jmp short error_exit
;***********************************************************************
; clean up and exit
;***********************************************************************
exit:
; set exit code to 0 (Success)
mov ax,4c00h
push ax
error_exit:
; restore the original disk parameter table pointer
mov cx,word ptr [parameter_pointer]
mov dx,word ptr [parameter_pointer+2]
push ds
xor ax,ax
mov ds,ax
assume ds:0000h
cli
mov word ptr ds:[0078h],cx
mov word ptr ds:[007ah],dx
sti
pop ds
assume ds:cseg
; park the heads on track 0
mov ah,0ch
xor cl,cl
xor dh,dh
mov dl,byte ptr [drive_number]
int 13h
pop ax
push ax
cmp al,0
jne error_out
; display format complete message
mov dx,offset exit_message
mov ah,09h
int 21h
error_out:
; restore the cursor
mov cx,word ptr [cursor]
mov ah,01h
int 10h
; terminate with exit code (0 = Success, else = Failure)
pop ax
int 21h
;***********************************************************************
; format subroutines
;***********************************************************************
;***********************************************************************
; information display during format
;***********************************************************************
display_format:
xor ah,ah
aam
or ax,3030h
mov byte ptr [format_track_number+1],al
cmp ah,30h
jne format_digit
mov ah,20h
format_digit:
mov byte ptr [format_track_number],ah
mov al,bl
xor ah,ah
aam
or ax,3030h
mov byte ptr [format_head_number],al
mov dx,offset format_display
mov ah,09h
int 21h
ret
;***********************************************************************
; information display during verification
;***********************************************************************
display_verify:
xor ah,ah
aam
or ax,3030h
mov byte ptr [verify_track_number+1],al
cmp ah,30h
jne verify_digit
mov ah,20h
verify_digit:
mov byte ptr [verify_track_number],ah
mov al,bl
xor ah,ah
aam
or ax,3030h
mov byte ptr [verify_head_number],al
mov dx,offset verify_display
mov ah,09h
int 21h
ret
;***********************************************************************
; increment the track number in the sector tables
;***********************************************************************
next_track:
xor ch,ch
mov cl,36
mov bx,offset sector_table_0
track_counter:
inc byte ptr [bx]
add bx,4
loop track_counter
ret
;***********************************************************************
; format (and possibly verify) both heads on one track
;***********************************************************************
format_track:
mov al,byte ptr [sector_table_0]
mov bl,0
; display formatting message
call display_format
mov byte ptr [retry_count],3
head_0_retry:
mov ah,5
mov al,byte ptr [sectors_track]
mov bx,offset sector_table_0
mov ch,byte ptr [bx]
mov cl,byte ptr [bx+2]
mov dh,byte ptr [bx+1]
mov dl,byte ptr [drive_number]
int 13h
jnc short head_0_ok
cmp ah,80h
jne no_timeout
mov dx,offset no_floppy_error
stc
ret
no_timeout:
cmp ah,03h
jne not_protected
mov dx,offset write_protect_error
stc
ret
not_protected:
dec byte ptr [retry_count]
jnz head_0_retry
mov dx,offset error_during_format
stc
ret
head_0_ok:
cmp byte ptr [verify],1
je verify_head_0
; check for proper floppy type
;
; this is done via a verification of tracks 0,
; 59, and 79, for head 0 only, for all 1.2 Mb disks
; not being verified, and on track 0 head 0 only, for
; 360 Kb, 720 Kb and 1.44 Mb disks not being verified.
;
; the following combinations will fail at track 0:
;
; 1: trying to format a 1.2 Mb floppy to 360 Kb
; 2: trying to format a 720 Kb floppy to 1.44 Mb *
; 3: trying to format a 1.44 Mb floppy to 720 Kb * !
;
; the following combination will fail at track 79:
;
; 1: trying to format a 360 Kb floppy to 1.2 Mb (it will
; probably fail sooner, but it is sure to here)
;
; notes:
;
; * - these combinations may not fail if the drive-
; controller combination does not properly detect
; the the floppy type.
;
; ! - this combination may not fail in 720 Kb drives.
;
; While certain non-standard combinations may not fail,
; either the data on the disk may be at risk, or your
; pocketbook may suffer, if you insist on using them.
cmp byte ptr [sector_table_0],0
je verify_type
cmp byte ptr [disk_size],2
je one_point_two
jmp short format_head_1
one_point_two:
cmp byte ptr [sector_table_0],59
je verify_type
cmp byte ptr [sector_table_0],79
je verify_type
jmp short format_head_1
verify_type:
mov ah,04h
int 13h
jnc format_head_1
mov dx,offset disk_type_error
stc
ret
verify_head_0:
pushf
pusha
mov al,byte ptr [sector_table_0]
mov bl,0
; display verifying message
call display_verify
popa
popf
mov ah,04h
int 13h
jnc format_head_1
mov dx,offset verify_error
stc
ret
format_head_1:
pushf
pusha
mov al,byte ptr [sector_table_0]
mov bl,1
; display formatting message
call display_format
popa
popf
mov byte ptr [retry_count],3
head_1_retry:
mov ah,5
mov al,byte ptr [sectors_track]
mov bx,offset sector_table_1
mov ch,byte ptr [bx]
mov cl,byte ptr [bx+2]
mov dh,byte ptr [bx+1]
mov dl,byte ptr [drive_number]
int 13h
jnc short head_1_ok
dec byte ptr [retry_count]
jnz head_1_retry
mov dx,offset error_during_format
stc
ret
head_1_ok:
cmp byte ptr [verify],1
je verify_head_1
format_return:
clc
ret
verify_head_1:
pushf
pusha
mov al,byte ptr [sector_table_0]
mov bl,1
; display verifying message
call display_verify
popa
popf
mov ah,04h
int 13h
jnc format_return
mov dx,offset verify_error
stc
ret
;***********************************************************************
; calculate the track, head, and sector for a disk write
;***********************************************************************
write_ths:
; check for a valid absolute sector number
cmp dx,word ptr [sectors_track]
jb write_ths_ok
stc
ret
write_ths_ok:
; calculate the sector number
div word ptr [sectors_track]
inc dl
; store the sector number
mov byte ptr [write_sector],dl
; calculate the head number and the track number
xor dx,dx
div word ptr [heads]
; store the head number
mov byte ptr [write_head],dl
; store the track number
mov word ptr [write_track],ax
clc
ret
;***********************************************************************
; write one sector to the disk
;***********************************************************************
write_disk:
; get the track number
mov dx,word ptr [write_track]
; shift the upper 2 bits of the track number
; into the upper 2 bits of the sector number
mov cl,06
shl dh,cl
; get the sector number
or dh,byte ptr [write_sector]
mov cx,dx
xchg ch,cl
; get the drive number
mov dl,byte ptr [drive_number]
; get the head number
mov dh,byte ptr [write_head]
; write one sector to the disk
mov ax,0301h
int 13h
ret
;***********************************************************************
; transfer system files
;***********************************************************************
bios_source_path:
db "d:\"
bios_source_filename:
db "IBMBIO.COM",000h,008h
db "$"
bios_destination_path:
db "d:\"
bios_destination_filename:
db "IBMBIO.COM",000h,008h
db "$"
dos_source_path:
db "d:\"
dos_source_filename:
db "IBMDOS.COM",000h,008h
db "$"
dos_destination_path:
db "d:\"
dos_destination_filename:
db "IBMDOS.COM",000h,008h
db "$"
cmd_source_path:
db "d:\"
cmd_source_filename:
db "COMMAND.COM",000h,008h
db "$"
cmd_destination_path:
db "d:\"
cmd_destination_filename:
db "COMMAND.COM",000h,008h
db "$"
load_system:
mov dx,offset file_copy_message
mov ah,09h
int 21h
; get default drive
mov ah,19h
int 21h
; set source drive
add al,41h
mov byte ptr [bios_source_path],al
mov byte ptr [dos_source_path],al
mov byte ptr [cmd_source_path],al
; set destination drive
mov al,byte ptr [drive_number]
add al,41h
mov byte ptr [bios_destination_path],al
mov byte ptr [dos_destination_path],al
mov byte ptr [cmd_destination_path],al
; copy IBMBIOS.COM
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset bios_source_path
mov di,offset bios_destination_path
call file_copy
jc load_error
; copy IBMDOS.COM
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset dos_source_path
mov di,offset dos_destination_path
call file_copy
jc load_error
; copy COMMAND.COM
mov bx,offset file_buffer
mov cx,word ptr [buffer_size]
mov si,offset cmd_source_path
mov di,offset cmd_destination_path
call file_copy
jc load_error
clc
ret
load_error:
stc
ret
;***********************************************************************
; copy a file
;
; input:
;
; bx = pointer to copy buffer
; cx = copy buffer size in bytes
; si = pointer to source path\filename
; di = pointer to destination path\filename
;***********************************************************************
source: dw ?
destination: dw ?
read_handle: dw ?
write_handle: dw ?
file_time: dw ?
file_date dw ?
file_attr: dw ?
bytes_read: dw ?
copy_buffer_size: dw ?
copy_buffer: dw ?
; file copy messages
file_not_found:
db " - error opening input file",00Dh,00Ah
db "$"
file_create_error:
db " - error creating output file",00Dh,00Ah
db "$"
file_read_error:
db " - error reading file",00Dh,00Ah
db "$"
file_write_error:
db " - error writing file",00Dh,00Ah
db "$"
file_copy:
mov word ptr [copy_buffer],bx
mov word ptr [copy_buffer_size],cx
mov word ptr [source],si
mov word ptr [destination],di
mov dx,word ptr [source]
mov ah,3dh
xor al,al
int 21h ; open source file
mov word ptr [read_handle],ax
jnc file_open
; display file not found message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [source]
call write_message
mov dx,offset file_not_found
call write_message
jmp load_error
file_open:
mov ax,5700h
mov bx,word ptr [read_handle]
int 21h ; get file time and date
mov word ptr [file_time],cx
mov word ptr [file_date],dx
mov ax,4300h
mov dx,word ptr [source]
int 21h ; get file attributes
mov word ptr [file_attr],cx
mov al,byte ptr [drive_number]
mov cx,0000h
mov dx,word ptr [destination]
mov ah,3ch
int 21h ; create destination file
mov word ptr [write_handle],ax
jnc copy_cmd
; display file not created message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [destination]
call write_message
mov dx,offset file_create_error
call write_message
jmp copy_error
copy_cmd:
call read_file
jnc file_read_ok
; display file read error message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [source]
call write_message
mov dx,offset file_read_error
call write_message
jmp copy_error
file_read_ok:
call write_file
jnc file_write_ok
; display file write error message
mov dx,offset cr_lf
call write_message
mov dx,word ptr [destination]
call write_message
mov dx,offset file_write_error
call write_message
jmp copy_error
file_write_ok:
cmp ax,word ptr [copy_buffer_size]
je copy_cmd
mov bx,word ptr [read_handle]
mov ah,3eh
int 21h ; close read_file
mov ax,5701h
mov bx,word ptr [write_handle]
mov cx,word ptr [file_time]
mov dx,word ptr [file_date]
int 21h ; set file time and date
mov bx,word ptr [write_handle]
mov ah,3eh
int 21h ; close write_file
mov ax,4301h
mov cx,word ptr [file_attr]
mov dx,word ptr [destination]
int 21h ; set file attributes
clc
ret
copy_error:
stc
ret
;***********************************************************************
; issue a file copy error message
;***********************************************************************
write_message:
mov ah,09h
int 21h
ret
;***********************************************************************
; read file block into buffer
;***********************************************************************
read_file:
mov cx,word ptr [copy_buffer_size]
mov bx,word ptr [read_handle]
mov dx,word ptr [copy_buffer]
mov ah,3fh
int 21h
mov word ptr [bytes_read],ax
mov cx,ax
ret
;***********************************************************************
; write file block from buffer
;***********************************************************************
write_file:
mov bx,word ptr [write_handle]
mov dx,word ptr [copy_buffer]
mov ah,40h
int 21h
ret
;***********************************************************************
; boot sector data (track 0, head 0, sector 1)
;***********************************************************************
boot_record:
;***********************************************************************
.8086 ; enable the 8086 instruction set
;***********************************************************************
jmp boot_strap ; skip over data areas
;***********************************************************************
; DOS data area
;***********************************************************************
oem_name: db "FMT 1.00"
bytes_sector: dw 512
sectors_cluster: db ? ; filled in before writing boot
reserved_sectors: dw 1
fats: db 2
directory_size: dw ? ; filled in before writing boot
small_total: dw ? ; filled in before writing boot
descriptor: db ? ; filled in before writing boot
sectors_fat: dw ? ; filled in before writing boot
sectors_track: dw ? ; filled in before writing boot
heads: dw 2
hidden_sectors: dd 0
big_total: dd 0
physical_drive: db 0
reserved: db 0
extended_boot: db 029h
sn_low: dw ? ; filled in before writing boot
sn_high: dw ? ; filled in before writing boot
volume_label: db "NO NAME "
fat_type: db "FAT12 "
;***********************************************************************
; bootstrap program data area
;***********************************************************************
sectors_directory: db ? ; filled in before writing boot
dir_start: dd ? ; filled in before writing boot
data_start: dd ? ; filled in before writing boot
track: dw ? ; boot program variable
head: db ? ; boot program variable
sector: db ? ; boot program variable
disk_table: db 11 dup (?) ; filled in before writing boot
bios_name: db "IBMBIO COM"
dos_name: db "IBMDOS COM"
; boot program messages
reset_message:
db 00Dh,00Ah,00Ah
db "Disk controller error ..."
db 000h
system_message:
db 00Dh,00Ah,00Ah
db "No system on disk or disk read error ..."
db 000h
retry_message:
db 00Dh,00Ah,00Ah
db "Press any key to retry boot."
db 000h
;***********************************************************************
boot_strap:
; temporarily disable interrupts
cli
; set the stack segment and the extra segment to 0000
; DOS loads the boot record at 0000:7c00,
; so put the stack just below it
xor ax,ax
mov es,ax
mov ss,ax
mov sp,7c00h
assume es:0000h,ss:0000h
; set up the parameters used by the BIOS program loader
lds si,es:[0078h]
mov bx,0078h
; save current disk parameter table
push ds
push si
push ss
push bx
; set the data segment to 0000
mov ds,ax
assume ds:0000h
; use the disk parameter table in the floppy boot record
mov word ptr [bx],7c00h+disk_table-boot_record
mov word ptr [bx+02],ax
; enable interrupts
sti
; reset the disk controller
int 13h
jnc reset_ok
; display reset error message
mov si,7c00h+offset reset_message-offset boot_record
call write_string
jmp not_bootable
reset_ok:
; get directory start sector (absolute sector number)
mov ax,word ptr ds:[7c00h+dir_start-boot_record]
mov dx,word ptr ds:[7c00h+dir_start-boot_record+2]
; get track, head, and sector
call calculate_ths
jnc dir_sector_ok
; display system error message
mov si,7c00h+offset system_message-offset boot_record
call write_string
jmp not_bootable
dir_sector_ok:
; set the offset of the disk read buffer
mov bx,0500h
; read the first directory sector
call read_disk
jc not_bootable
; check directory for the BIOS file
; (it must be the first directory entry)
mov di,bx
mov cx,11
mov si,7c00h+offset bios_name-offset boot_record
rep cmpsb
jz dir_read_ok
; display system error message
mov si,7c00h+offset system_message-offset boot_record
call write_string
jmp not_bootable
dir_read_ok:
; check directory for the DOS file
; (it must be the second directory entry)
lea di,[bx+32]
mov si,7c00h+offset dos_name-offset boot_record
mov cx,11
rep cmpsb
; valid directory, attempt to boot from the disk
jz system_found
; display system error message
mov si,7c00h+offset system_message-offset boot_record
call write_string
jmp not_bootable
;***********************************************************************
system_found:
; get the data start sector (absolute sector number)
mov ax,word ptr ds:[7c00h+data_start-boot_record]
mov dx,word ptr ds:[7c00h+data_start-boot_record+2]
; set the offset of the disk read buffer
mov bx,0700h
; read 3 sectors (the length of the BIOS program loader)
mov cx,3
read_next:
push ax
push cx
push dx
; get track, head, and sector
call calculate_ths
jnb ok_to_read
; clean up the stack
pop ax
pop ax
pop ax
; display system error message
mov si,7c00h+offset system_message-offset boot_record
call write_string
jmp not_bootable
ok_to_read:
call read_disk
pop dx
pop cx
pop ax
jnc disk_read_ok
; display system error message
mov si,7c00h+offset system_message-offset boot_record
call write_string
jmp not_bootable
disk_read_ok:
; increment the sector to read
add ax,1
adc dx,0
; bump the offset of the read buffer by the sector size
add bx,word ptr ds:[7c00h+bytes_sector-boot_record]
loop read_next
; set up the parameters for the BIOS program loader
; get the media descriptor
mov ch,byte ptr ds:[7c00h+descriptor-boot_record]
; get the drive number
mov dl,byte ptr ds:[7c00h+physical_drive-boot_record]
; get the data start sector (absolute sector number)
mov ax,word ptr ds:[7c00h+data_start-boot_record+2]
mov bx,word ptr ds:[7c00h+data_start-boot_record]
; execute the BIOS program loader
jmp far ptr program_loader
;***********************************************************************
not_bootable:
; display retry message
mov si,7c00h+offset retry_message-offset boot_record
call write_string
; wait for a key to be pressed
xor ah,ah
int 16h
; clean up the stack
pop si
pop ds
pop [si]
pop [si+2]
; try to boot the system again
int 19h
;***********************************************************************
; bootstrap subroutines
;***********************************************************************
write_string:
; get one character
lodsb
; check for end of ASCIIZ string
or al,al
jnz next_char
ret
next_char:
; write one character to the screen
mov ah,0eh
; use video page 0, normal white
mov bx,0007h
int 10h
jmp write_string
;***********************************************************************
read_disk:
; get the track number
mov dx,word ptr ds:[7c00h+track-boot_record]
; shift the upper 2 bits of the track number
; into the upper 2 bits of the sector number
mov cl,06
shl dh,cl
; get the sector number
or dh,byte ptr ds:[7c00h+sector-boot_record]
mov cx,dx
xchg ch,cl
; get the drive number
mov dl,byte ptr ds:[7c00h+physical_drive-boot_record]
; get the head number
mov dh,byte ptr ds:[7c00h+head-boot_record]
; read one sector from the disk
mov ax,0201h
int 13h
ret
;***********************************************************************
calculate_ths:
; check for valid absolute sector number
cmp dx,word ptr ds:[7c00h+sectors_track-boot_record]
jb ths_ok
stc
ret
ths_ok:
; calculate the sector number
div word ptr ds:[7c00h+sectors_track-boot_record]
inc dl
; store the sector number
mov byte ptr ds:[7c00h+sector-boot_record],dl
; calculate the head number and the track number
xor dx,dx
div word ptr ds:[7c00h+heads-boot_record]
; store the head number
mov byte ptr ds:[7c00h+head-boot_record],dl
; store the track number
mov word ptr ds:[7c00h+track-boot_record],ax
clc
ret
;***********************************************************************
; adjust the boot record size to 512 bytes
;***********************************************************************
fill: db (512-(offset fill-offset boot_record)-2) dup (0)
;***********************************************************************
; boot sector signature
;***********************************************************************
signature: dw 0AA55h
;***********************************************************************
; end of boot sector data
;***********************************************************************
;***********************************************************************
; FAT and directory data
;***********************************************************************
; the first FAT sector has the media descriptor byte
fat_record:
db ? ; filled in before writing FAT
db 0ffh,0ffh
db 509 dup (0)
; other FAT sectors and directory sectors are all zeros
fat_dir_record:
db 512 dup (0)
;***********************************************************************
; copyright information
;***********************************************************************
version: db "FMT version 1.00 23-JAN-1990",000h
copyright: db "Copyright (C) 1990 by Clair Alan Hardesty",000h
;***********************************************************************
; put file copy buffer after code and other data
;***********************************************************************
file_buffer:
; buffer space starts here
cseg ends
end entry_point
;***********************************************************************
; end of Fmt.asm
;***********************************************************************